// StaticTreeBarrier.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "StaticTreeBarrier.h"
#include "Test.h"
#include "Globals.h"
#include <iostream>

// the static works with 4 threads radix 3 OR 3 threads radix 2
#define FAN_OUT 3

using namespace std;

StaticTreeBarrier *g_bar = new StaticTreeBarrier(Globals::numberOfThreads, FAN_OUT);

// recursive tree constructor
void StaticTreeBarrier::build(Node* parent, int depth)
{
	// is this node is a leaf?
    if (depth == 0)
	{
		// no childred for leaf nodes.
		_leaf[_leaves++] = new Node(parent, 0);
    } else {
		Node* myNode = new Node(parent, _radix);
		_leaf[_leaves++] = myNode;
		for (int i = 0; i < _radix; i++)
		{
			build(myNode, depth - 1);
	    }
	}
}

void StaticTreeBarrier::Node::await()
{
	int mySense = g_bar->threadSense.get();

    if (children != 0)
	{
		while (childCount.get() > 0) {};  // spin until children done
		childCount.set(children);         // prepare for next round
    }
    
	if (parent != NULL)
	{ // not root?
		parent->childCount.getAndDecrement();//childDone();				// indicate child subtree completion
		while (g_bar->global_sense != mySense) 
		{
			//Thread::yield();// use this when running on core2 due machine.
		}; // wait for global sense to change
	} else {
		g_bar->global_sense = mySense;   // am root: toggle global sense
		MB();
	}

	int myNewSense = (mySense + 1) % 2;
	g_bar->threadSense.set(myNewSense);
}

void StaticTreeBarrier::await()
{
	int me = threadId.get();
	_leaf[me]->await();
}


void StaticTreeBarrier::initThreadLocals(int me)
{
	threadId.set(me);
}

/// MAIN

int main()
{
	TestFactory factory;

	Test* test = factory.createTest(g_bar, Counter);

	test->performTest();
}
